#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import json
import os
import stat
import sys

from common.cleaner import clear
from common.common import execute_cmd
from common.const import SysData
from sqlserver import log
from sqlserver.commons.common import check_del_dir_or_file, output_tmp_info
from sqlserver.commons.const import ParamConstant, JobData
from sqlserver.commons.sqlserver_parse_param import VDIAPINAME
from sqlserver.commons.sqlserver_utils import SqlServerUtils
from sqlserver.sqlserver_base import SQLServerBase
from sqlserver.sqlserver_cluster_instance_resource import SqlServerClusterInstanceResource


class SqlServerClusterResource:
    def __init__(self, p_id, json_param):
        self.m_resource_base = SqlServerClusterInstanceResource(p_id, "", json_param)
        self._json_param = json_param
        self.m_func_type = ""
        self.m_instance_name = ""
        self.m_hostname = ""
        self.m_authentication_type = 0
        self.m_check_output = {'code': 200, 'bobyErr': 0, 'message': ''}
        """
        集群下节点信息
        """
        self.nodes = []
        """
        集群信息
        """
        self.m_resource_output = {
            "id": "",
            "name": "",
            "type": "Database",
            "subType": "SQLServer-cluster",
            "endpoint": "",
            "role": 1,
            "nodes": [],
            "extendInfo": {"quorum_type": 0,
                           "quorum_state": 0}

        }
        self.m_username = ""
        self.m_password = ""

    @staticmethod
    def check_result_path():
        """
        check result path exit or not
        """
        log.info("check result path exit or not")
        if os.path.exists(ParamConstant.RESULT_PATH):
            return True
        else:
            log.error("The result file path does not exist!")
            return False

    @staticmethod
    def write_result_to_file(in_str):
        log.info("Enter write_result_to_file")
        str_str = json.dumps(in_str)
        file_name = "{}{}".format("result", JobData.PID)
        file_path = os.path.join(ParamConstant.RESULT_PATH, file_name)
        output_tmp_info(file_path, str_str)
        log.info("Leave write_result_to_file")

    @staticmethod
    def write_to_ps_script(cmd):
        tmp_script = os.path.join(ParamConstant.PARAM_FILE_PATH, "temp1.ps1")
        flags = os.O_WRONLY | os.O_CREAT
        modes = stat.S_IWUSR | stat.S_IRUSR
        with os.fdopen(os.open(tmp_script, flags, modes), 'w+') as out_file:
            out_file.write(cmd)

    def clear_pwd(self):
        clear(self.m_password)

    def exec_pw_shell(self, shell_cmd):
        try:
            self.write_to_ps_script(shell_cmd)
        except Exception as e:
            log.error(f'{str(e)}')
            return False, ''
        tmp_script = os.path.join(ParamConstant.PARAM_FILE_PATH, "temp1.ps1")
        cmds = f'{VDIAPINAME.ps_loc} {tmp_script}'
        ret, std_out, std_err = execute_cmd(cmds)
        if int(ret) != 0:
            return False, ''
        try:
            os.remove(tmp_script)
        except Exception as err:
            log.error(f"Delete file temp1.ps1 failed: {err}!")
        return True, std_out.split('\n')

    def get_cluster_name(self):
        log.info("Enter get_cluster_name....")
        flags, std_out = self.exec_pw_shell("Get-Cluster")
        if not flags:
            return False
        self.m_resource_output['name'] = std_out[3]
        log.info("Leave get_cluster_name....")
        return True

    def get_cluster_member(self):
        log.info("Enter get_cluster_member....")
        flags, std_out = self.exec_pw_shell("Get-ClusterNode")
        if not flags:
            return False
        indexs = 0
        std_out_lens = len(std_out)
        self.m_hostname = self._json_param.get("job", {}).get("protectObject", {}) \
            .get("extendInfo", {}).get("networkName", "")
        if self.m_hostname == "":
            self.m_hostname = SqlServerUtils.get_hostname()
        for member in std_out:
            if indexs < 3:
                indexs += 1
                continue
            if indexs == (std_out_lens - 3):
                break
            indexs += 1
            member_split = member.split()
            tmp_name = member_split[0]
            tmp_id = member_split[1]
            tmp_state_str = member_split[2]
            if tmp_state_str == 'UP':
                tmp_state = 0
            else:
                tmp_state = -1
            tmp_nodes = {
                "id": tmp_id,
                "name": "",
                "type": "Database",
                "subType": "SQLServer-instance",
                "endpoint": self.m_hostname,
                "role": 1,
                "extendInfo": {
                    "memberState": tmp_state,
                    "instanceName": "",
                    "serverNmae": "",
                }
            }
            if tmp_name == self.m_hostname:
                tmp_nodes['endpoint'] = self.m_hostname
            nds = self.m_resource_output.get('nodes', {})
            nds.append(tmp_nodes)
        log.info("Leave get_cluster_member....")
        return True

    def get_windows_input(self, in_str):
        """
        get input from system command line
        """
        log.info("Get input from system command line")
        self.m_func_type = in_str

    def list_cluster_resource(self):
        log.info("Enter list_cluster_resource......")
        ret = self.get_cluster_name()
        if not ret:
            SqlServerClusterResource.write_result_to_file(self.m_check_output)
            return False
        ret = self.get_cluster_member()
        if not ret:
            SqlServerClusterResource.write_result_to_file(self.m_check_output)
            return False
        SqlServerClusterResource.write_result_to_file(self.m_resource_output)
        log.info("Leave list_cluster_resource......")
        return True


if __name__ == '__main__':
    log.info("Running main....")
    args = sys.argv[1:]
    JobData.PID = sys.argv[2]
    for line in sys.stdin:
        SysData.SYS_STDIN = line
        break
    FILE_NAME = "{}{}".format("param", JobData.PID)
    FILE_PATH = os.path.join(ParamConstant.PARAM_FILE_PATH, FILE_NAME)
    if not os.path.exists(FILE_PATH):
        sys.exit(1)
    JSON_TMP = SQLServerBase.read_temp_file(FILE_PATH)
    if len(args) < 2:
        sys.exit(1)
    newInstance = SqlServerClusterResource(JobData.PID, JSON_TMP)
    if not newInstance.check_result_path():
        sys.exit(1)
    newInstance.get_windows_input(sys.argv[1])
    if newInstance.m_func_type == "QueryCluster":
        newInstance.list_cluster_resource()
        check_del_dir_or_file(FILE_PATH)
        newInstance.clear_pwd()
        clear(SysData.SYS_STDIN)
    elif newInstance.m_func_type == "CheckApplication":
        newInstance.m_resource_base.authentication()
        check_del_dir_or_file(FILE_PATH)
        newInstance.clear_pwd()
        clear(SysData.SYS_STDIN)
    else:
        log.error("Wrong input from command line!")
